﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Collections.ObjectModel;

namespace Chaos.stream
{
    public class istream_xml : stream
    {
        XmlReader reader;
        factory factory;

        public istream_xml(factory in_factory)
        {
            factory = in_factory;
        }

        public void open(String in_FilePath)
        {
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.IgnoreWhitespace = true;
            reader = XmlTextReader.Create(in_FilePath, settings);
            reader.Read();
        }

        public void open(Stream in_Stream)
        {
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.IgnoreWhitespace = true;
            reader = XmlTextReader.Create(in_Stream, settings);
            reader.Read();
        }

        public void movetoelement(String in_String)
        {
            while (reader.Name != in_String)
            {
                reader.Read();
            }
        }

        public void close()
        {
            reader.Close();
        }

        public stream begin(String in_String)
        {
            movetoelement(in_String);
            return this;
        }

        public stream end(String in_String)
        {
            try
            {
                reader.Read();
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(in_String);
                System.Diagnostics.Debug.WriteLine(e.ToString());
            }
            return this;
        }

        public stream serialize(String in_String, ref bool o_Value)
        {
            String s = reader.GetAttribute(in_String);
            o_Value = bool.Parse(s);
            return this;
        }

        public stream serialize(String in_String, ref int o_Value)
        {
            String s = reader.GetAttribute(in_String);
            o_Value = int.Parse(s);
            return this;
        }

        public stream serialize(String in_String, ref float o_Value)
        {
            String s = reader.GetAttribute(in_String);
            o_Value = float.Parse(s);
            return this;
        }

        public stream serialize(String in_String, ref double o_Value)
        {
            String s = reader.GetAttribute(in_String);
            o_Value = double.Parse(s);
            return this;
        }

        public stream serialize(String in_String, ref String o_Value)  
        {
            o_Value = reader.GetAttribute(in_String);
            return this;
        }

        public stream serialize(String in_String, ref streamable o_Value)
        {
            try
            {
                movetoelement(in_String);

                reader.ReadStartElement(in_String);
                if (o_Value == null)
                {
                    o_Value = factory.create(reader.Name);
                    if (o_Value == null)
                    {
                        System.Diagnostics.Debug.WriteLine("serialize failed to create " + reader.Name);
                    }
                }
                o_Value.serialize(this);
                reader.ReadEndElement();
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(in_String);
                System.Diagnostics.Debug.WriteLine(e.ToString());
            }
            return this;
        }

        public stream serialize(String in_String, ref Enum o_Value)
        {
            String s = reader.GetAttribute(in_String);
            o_Value = (System.Enum)Enum.Parse(o_Value.GetType(), s);
            return this;
        }
        
        public stream serialize(String in_String, ref int[] o_Value)
        {
            movetoelement(in_String);
            reader.Read();

            List<int> tmp = new List<int>();
            while (reader.Name == "step")
            {
                reader.ReadStartElement("step");
                String s = reader.ReadString();
                tmp.Add(int.Parse(s));                
                reader.ReadEndElement();
            }

            o_Value = new int[tmp.Count];
            tmp.CopyTo(o_Value);

            return this;            
        }

        public stream serialize(String in_String, ref float[] o_Value)
        {
            movetoelement(in_String);
            reader.Read();

            List<float> tmp = new List<float>();
            while (reader.Name == "step")
            {
                reader.ReadStartElement("step");
                String s = reader.ReadString();
                tmp.Add(float.Parse(s));
                reader.ReadEndElement();
            }

            o_Value = new float[tmp.Count];
            tmp.CopyTo(o_Value);

            return this; 
        }

        public stream serialize(String in_String, ref double[] o_Value)
        {
            movetoelement(in_String);
            reader.Read();

            List<double> tmp = new List<double>();
            while (reader.Name == "step")
            {
                reader.ReadStartElement("step");
                String s = reader.ReadString();
                tmp.Add(double.Parse(s));
                reader.ReadEndElement();
            }

            o_Value = new double[tmp.Count];
            tmp.CopyTo(o_Value);

            return this;
        }

        public stream serialize(String in_String, ref String[] o_Value)
        {
            movetoelement(in_String);
            reader.ReadStartElement(in_String);

            List<String> tmp = new List<String>();
            while (reader.Name == "step")
            {
                reader.ReadStartElement("step");
                String s = reader.ReadString();
                tmp.Add(s);
                reader.ReadEndElement();
            }

            o_Value = new String[tmp.Count];
            tmp.CopyTo(o_Value);

            return this; 
        }

        public stream serialize(String in_String, ref streamable[] o_Value)
        {
            try
            {
                movetoelement(in_String);
                reader.ReadStartElement(in_String);

                foreach (streamable s in o_Value)
                {
                    s.serialize(this);
                }
                reader.ReadEndElement();
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(in_String);
                System.Diagnostics.Debug.WriteLine(e.ToString());
            }

            return this; 
        }

        public stream serialize<T>(String in_String, ref ObservableCollection<T> in_Value)
        {
            try
            {
                movetoelement(in_String);
                reader.ReadStartElement(in_String);

                int count = 0;
                while (reader.Name != in_String)
                {
                    streamable s = null;
                    if (in_Value.Count <= count)
                    {
                        s = factory.create(reader.Name);
                        in_Value.Add((T)s);
                    }
                    else
                    {
                        s = in_Value[count] as streamable;
                    }
                    s.serialize(this);
                    count++;   
                }
                reader.ReadEndElement();
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(in_String);
                System.Diagnostics.Debug.WriteLine(e.ToString());
            }
            return this; 
        }

        public bool isoutputstream()
        {
            return false;
        }

        public bool isinputstream()
        {
            return true;
        }

    }
}
